Ajax.Autocompleter blanks out page when used in an Internet Explorer IE framed jsp

142 views
Skip to first unread message

krishna

unread,
Mar 11, 2009, 12:11:46 AM3/11/09
to Prototype & script.aculo.us
My autocompleter blanks the whole frame whenever I start typing in my
textbox in my jsp page loaded in a frame whereas it is supposed to
load my div with the available options. This is my first piece of
nice code (autocompleter) written using Prototype 1.6.0.3 downloaded
from the prototype website, Scriptaculous 1.8.0_pre1downloaded from
the book Pragmatic Prototype and script.aculo.us source code which
says REQUIRED_PROTOTYPE: '1.6.0', controls.js and effects.js only
mention 2005-2007 and provide no version information whatsoever.

I have modified the Ajax.Autocompleter quite a buit to include the
what fields I want to display in the dropdown autocomplete and what
fields I want to update based on the keys of the selected jsonObject
from the jsonobject array passed to prototype. However, the .jsp (Java
Server Page) works great in Firefox with and without a frame, but
fails in IE when used outside a frame, i.e., as a stand alone page,
but fails within a frame.

I always thought that these existing controls and effects in
scriptaculous are cross-browser compatible and all issues are already
taken care of, am I missing something here?

jsp usage:

<head>
...
<link rel="stylesheet" type="text/css"
href="<%=request.getContextPath()%>/pages/styles/autocomplete.css" />
<script type="text/javascript"
src="<%=request.getContextPath()%>/pages/javascript/prototype/
prototype.js"></script>
<script type="text/javascript"
src="<%=request.getContextPath()%>/pages/javascript/prototype/
scriptaculous.js?load=effects,controls"></script>
...
document.observe('dom:loaded', function() {

new Ajax.Autocompleter('nameId', 'nameChoicesDivId', '/
someAction.do?method=autoCompletename',
['name','age','ssn'], ['name','age','ssn'] , true);
});

...
</head>

<tr>
<td colspan="3"><input type="text" name="name" id="nameId"
size="70"/> </td>
<td class="boldLabel" ><input type="text" name="age" id="ageId"/></
td>
<td class="boldLabel" ><input type="text" name="ssn" id="ssnId"/></
td>
</tr>
<tr>
<td colspan="5">
<div id="nameChoicesDivId" class="autocomplete"></div>
</td>
</tr>


css:
h1 { font-size: 1.5em; }

div.autocomplete {
position: absolute;
width: 250px; /* will be adjusted by script.aculo.us */
background-color: white; border: 1px solid #888;
margin: 0px; padding: 0px;
}
div.autocomplete ul {
list-style-type: none; margin: 0px; padding: 0px;
}
div.autocomplete ul li.selected { background-color: #ff9;}
div.autocomplete ul li {
list-style-type: none; display: block;
font-family: sans-serif; font-size: smaller; color: #444;
margin: 0; padding: 0.1em; height: 1.5em; line-height: 1.5em;
cursor: pointer;
}


Any help will be appreciated.

Regards
Radha Krishna

david

unread,
Mar 11, 2009, 7:08:44 AM3/11/09
to Prototype & script.aculo.us
Hi krishna,

Is there a possibility to test a live exemple, because the problem
with autocompleter is that it need ajax call.
btw, I look at you're code, and see some strange initialisation of the
autocomplter:

your initialisation is
new Ajax.Autocompleter('nameId', 'nameChoicesDivId', '/someAction.do?
method=autoCompletename',['name','age','ssn'], ['name','age','ssn'] ,
true);

and the doc initialise autocompleter as
new Ajax.Autocompleter(id_of_text_field, id_of_div_to_populate, url,
options);

So in your exemple, the option which should be an object is an array :
((
that a possible cause of the crash ?!?

--
david

david

unread,
Mar 11, 2009, 7:11:26 AM3/11/09
to Prototype & script.aculo.us
Hi again krishna,

try downloading the latest version of scriptaculous at:
http://script.aculo.us/dist/scriptaculous-js-1.8.2.zip

that could be another rerason.

--
david

krishna

unread,
Mar 11, 2009, 9:53:41 AM3/11/09
to Prototype & script.aculo.us
Hi David,

Thanks for your prompt reply. I will download the latest scriptaculous
that you suggested and modify it and try again!

Until then, as I said in my post, I tried to modify the controls.js a
lot by customizing it to be able to display 1) what fields I want to
display in the auto-completion div and also what fields I want to
update. Here is the code:

/***
* Excerpted from "Prototype and script.aculo.us",
* published by The Pragmatic Bookshelf.
* Copyrights apply to this code. It may not be used to create
training material,
* courses, books, articles, and the like. Contact us if you are in
doubt.
* We make no guarantees that this code is fit for any purpose.
* Visit http://www.pragmaticprogrammer.com/titles/cppsu for more book
information.
***/
// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us,
http://mir.aculo.us)
// (c) 2005-2007 Ivan Krstic (http://blogs.law.harvard.edu/
ivan)
// (c) 2005-2007 Jon Tirsen (http://www.tirsen.com)
// Contributors:
// Richard Livsey
// Rahul Bhargava
// Rob Wills
//
// script.aculo.us is freely distributable under the terms of an MIT-
style license.
// For details, see the script.aculo.us web site: http://script.aculo.us/

// Autocompleter.Base handles all the autocompletion functionality
// that's independent of the data source for autocompletion. This
// includes drawing the autocompletion menu, observing keyboard
// and mouse events, and similar.
//
// Specific autocompleters need to provide, at the very least,
// a getUpdatedChoices function that will be invoked every time
// the text inside the monitored textbox changes. This method
// should get the text for which to provide autocompletion by
// invoking this.getToken(), NOT by directly accessing
// this.element.value. This is to allow incremental tokenized
// autocompletion. Specific auto-completion logic (AJAX, etc)
// belongs in getUpdatedChoices.
//
// Tokenized incremental autocompletion is enabled automatically
// when an autocompleter is instantiated with the 'tokens' option
// in the options parameter, e.g.:
// new Ajax.Autocompleter('id','upd', '/url/', { tokens: ',' });
// will incrementally autocomplete with a comma as the token.
// Additionally, ',' in the above example can be replaced with
// a token array, e.g. { tokens: [',', '\n'] } which
// enables autocompletion on multiple tokens. This is most
// useful when one of the tokens is \n (a newline), as it
// allows smart autocompletion after linebreaks.

if(typeof Effect == 'undefined')
throw("controls.js requires including script.aculo.us' effects.js
library");

var Autocompleter = { }
Autocompleter.Base = Class.create({
baseInitialize: function(element, update, options) {
element = $(element)
this.element = element;
this.update = $(update);
this.hasFocus = false;
this.changed = false;
this.active = false;
this.index = 0;
this.entryCount = 0;
this.oldElementValue = this.element.value;

if(this.setOptions)
this.setOptions(options);
else
this.options = options || { };

this.options.paramName = this.options.paramName ||
this.element.name;
this.options.tokens = this.options.tokens || [];
this.options.frequency = this.options.frequency || 0.4;
this.options.minChars = this.options.minChars || 1;
this.options.onShow = this.options.onShow ||
function(element, update){
if(!update.style.position ||
update.style.position=='absolute') {
update.style.position = 'absolute';
Position.clone(element, update, {
setHeight: false,
offsetTop: element.offsetHeight
});
}
Effect.Appear(update,{duration:0.15});
};
this.options.onHide = this.options.onHide ||
function(element, update){ new Effect.Fade(update,{duration:
0.15}) };

if(typeof(this.options.tokens) == 'string')
this.options.tokens = new Array(this.options.tokens);
// Force carriage returns as token delimiters anyway
if (!this.options.tokens.include('\n'))
this.options.tokens.push('\n');

this.observer = null;

this.element.setAttribute('autocomplete','off');

Element.hide(this.update);

Event.observe(this.element, 'blur', this.onBlur.bindAsEventListener
(this));
Event.observe(this.element, 'keypress',
this.onKeyPress.bindAsEventListener(this));
},

show: function() {
if(Element.getStyle(this.update, 'display')=='none')
this.options.onShow(this.element, this.update);
if(!this.iefix &&
(Prototype.Browser.IE) &&
(Element.getStyle(this.update, 'position')=='absolute')) {
new Insertion.After(this.update,
'<iframe id="' + this.update.id + '_iefix" '+

'style="display:none;position:absolute;filter:progid:DXImageTransform.Microsoft.Alpha
(opacity=0);" ' +
'src="javascript:false;" frameborder="0" scrolling="no"></
iframe>');
this.iefix = $(this.update.id+'_iefix');
}
if(this.iefix) setTimeout(this.fixIEOverlapping.bind(this), 50);
},

fixIEOverlapping: function() {
Position.clone(this.update, this.iefix, {setTop:(!
this.update.style.height)});
this.iefix.style.zIndex = 1;
this.update.style.zIndex = 2;
Element.show(this.iefix);
},

hide: function() {
this.stopIndicator();
if(Element.getStyle(this.update, 'display')!='none')
this.options.onHide(this.element, this.update);
if(this.iefix) Element.hide(this.iefix);
},

startIndicator: function() {
if(this.options.indicator) Element.show(this.options.indicator);
},

stopIndicator: function() {
if(this.options.indicator) Element.hide(this.options.indicator);
},

onKeyPress: function(event) {
if(this.active)
switch(event.keyCode) {
case Event.KEY_TAB:
case Event.KEY_RETURN:
this.selectEntry();
Event.stop(event);
case Event.KEY_ESC:
this.hide();
this.active = false;
Event.stop(event);
return;
case Event.KEY_LEFT:
case Event.KEY_RIGHT:
return;
case Event.KEY_UP:
this.markPrevious();
this.render();
if(Prototype.Browser.WebKit) Event.stop(event);
return;
case Event.KEY_DOWN:
this.markNext();
this.render();
if(Prototype.Browser.WebKit) Event.stop(event);
return;
}
else
if(event.keyCode==Event.KEY_TAB ||
event.keyCode==Event.KEY_RETURN ||
(Prototype.Browser.WebKit > 0 && event.keyCode == 0)) return;

this.changed = true;
this.hasFocus = true;

if(this.observer) clearTimeout(this.observer);
this.observer =
setTimeout(this.onObserverEvent.bind(this),
this.options.frequency*1000);
},

activate: function() {
this.changed = false;
this.hasFocus = true;
this.getUpdatedChoices();
},

onHover: function(event) {
var element = Event.findElement(event, 'LI');
if(this.index != element.autocompleteIndex)
{
this.index = element.autocompleteIndex;
this.render();
}
Event.stop(event);
},

onClick: function(event) {
var element = Event.findElement(event, 'LI');
this.index = element.autocompleteIndex;
this.selectEntry();
this.hide();
},

onBlur: function(event) {
// needed to make click events working
setTimeout(this.hide.bind(this), 250);
this.hasFocus = false;
this.active = false;
},

render: function() {
if(this.entryCount > 0) {
for (var i = 0; i < this.entryCount; i++)
this.index==i ?
Element.addClassName(this.getEntry(i),"selected") :
Element.removeClassName(this.getEntry(i),"selected");
if(this.hasFocus) {
this.show();
this.active = true;
}
} else {
this.active = false;
this.hide();
}
},

markPrevious: function() {
if(this.index > 0) this.index--
else this.index = this.entryCount-1;
this.getEntry(this.index).scrollIntoView(true);
},

markNext: function() {
if(this.index < this.entryCount-1) this.index++
else this.index = 0;
this.getEntry(this.index).scrollIntoView(false);
},

getEntry: function(index) {
return this.update.firstChild.childNodes[index];
},

getCurrentEntry: function() {
return this.getEntry(this.index);
},

selectEntry: function() {
this.active = false;
this.updateElement(this.getCurrentEntry());
},

updateElement: function(selectedElement) {

var lookupFieldName = this.element.name;

// this is the complete json resultset
var jsonObject = this.jsonResultSet;

// get the index of the row that is clicked
var jsonObj = this.jsonResultSet[selectedElement.id];

// check if it is not the same key as the lookupFieldName
// which is updated next!
// this checks if there are any other fields passed by user in the
json object
// whose keys are available as "name" parameters, and their values
will be updated!
//Object.keys(jsonObj).each(function(jsonObjKey){
// if(!($(jsonObjKey + 'Id') == null))
// {
// $(jsonObjKey + 'Id').value = jsonObj[jsonObjKey];
// }
//});

// the autocomplete field is mandatory in the jsonObj
if(jsonObj[lookupFieldName] == null)
{
alert('no key was found in the json object with the key: ' +
lookupFieldName + ' which is mandatory!');
}
else
{
$(lookupFieldName + 'Id').value = jsonObj[lookupFieldName];
}

// update the fields that were requested to be udpated
this.addFieldsToUpdate.each(function(fieldKey){
if(!($(fieldKey + 'Id') == null))
{
if(jsonObj[fieldKey] != null)
{
$(fieldKey + 'Id').value = jsonObj[fieldKey];
}
else if(this.warnIfNotFound)
{
alert('no key was found in the json object with the key: ' +
fieldKey);
}
}
else if(this.warnIfNotFound)
{
alert('no element was found in the jsp with the name: ' + fieldKey
+ ' that can be updated');
}
});

if (this.options.updateElement) {
this.options.updateElement(selectedElement);
return;
}
var value = '';
if (this.options.select) {
var nodes = $(selectedElement).select('.' + this.options.select)
|| [];
if(nodes.length>0) value = Element.collectTextNodes(nodes[0],
this.options.select);
} else
value = Element.collectTextNodesIgnoreClass(selectedElement,
'informal');

var bounds = this.getTokenBounds();
if (bounds[0] != -1) {
var newValue = this.element.value.substr(0, bounds[0]);
var whitespace = this.element.value.substr(bounds[0]).match(/^\s
+/);
if (whitespace)
newValue += whitespace[0];

// commented to update directly based on key passed and whose id
= key + 'Id'
// this.element.value = newValue + value +
this.element.value.substr(bounds[1]);
} else {
// this.element.value = value;
}
this.oldElementValue = this.element.value;
this.element.focus();

if (this.options.afterUpdateElement)
this.options.afterUpdateElement(this.element, selectedElement);
},

updateChoices: function(choices) {
if(!this.changed && this.hasFocus) {
this.update.innerHTML = choices;
Element.cleanWhitespace(this.update);
Element.cleanWhitespace(this.update.down());

if(this.update.firstChild && this.update.down().childNodes) {
this.entryCount =
this.update.down().childNodes.length;
for (var i = 0; i < this.entryCount; i++) {
var entry = this.getEntry(i);
entry.autocompleteIndex = i;
this.addObservers(entry);
}
} else {
this.entryCount = 0;
}

this.stopIndicator();
this.index = 0;

if(this.entryCount==1 && this.options.autoSelect) {
this.selectEntry();
this.hide();
} else {
this.render();
}
}
},

addObservers: function(element) {
Event.observe(element, "mouseover",
this.onHover.bindAsEventListener(this));
Event.observe(element, "click", this.onClick.bindAsEventListener
(this));
},

onObserverEvent: function() {
this.changed = false;
this.tokenBounds = null;
if(this.getToken().length>=this.options.minChars) {
this.getUpdatedChoices();
} else {
this.active = false;
this.hide();
}
this.oldElementValue = this.element.value;
},

getToken: function() {
var bounds = this.getTokenBounds();
return this.element.value.substring(bounds[0], bounds[1]).strip();
},

getTokenBounds: function() {
if (null != this.tokenBounds) return this.tokenBounds;
var value = this.element.value;
if (value.strip().empty()) return [-1, 0];
var diff = arguments.callee.getFirstDifferencePos(value,
this.oldElementValue);
var offset = (diff == this.oldElementValue.length ? 1 : 0);
var prevTokenPos = -1, nextTokenPos = value.length;
var tp;
for (var index = 0, l = this.options.tokens.length; index < l; +
+index) {
tp = value.lastIndexOf(this.options.tokens[index], diff + offset
- 1);
if (tp > prevTokenPos) prevTokenPos = tp;
tp = value.indexOf(this.options.tokens[index], diff + offset);
if (-1 != tp && tp < nextTokenPos) nextTokenPos = tp;
}
return (this.tokenBounds = [prevTokenPos + 1, nextTokenPos]);
}
});

Autocompleter.Base.prototype.getTokenBounds.getFirstDifferencePos =
function(newS, oldS) {
var boundary = Math.min(newS.length, oldS.length);
for (var index = 0; index < boundary; ++index)
if (newS[index] != oldS[index])
return index;
return boundary;
};

// Base class initializer
Ajax.Autocompleter = Class.create(Autocompleter.Base, {
initialize: function(element, update, url, addFieldsToDisplay,
addFieldsToUpdate, warnIfNotFound, options) {
this.baseInitialize(element, update, options);
this.options.asynchronous = true;
this.options.onComplete = this.onComplete.bind(this);
this.options.defaultParams = this.options.parameters || null;

this.url = url;

// additional fields used in the div drop down and field updation
logic
this.jsonResultSet = null; // complete jsonResultSet
this.addFieldsToDisplay = addFieldsToDisplay;
// string array of additionalField keys that must be displayed
// in the drop down when performing the autoCompletion
this.addFieldsToUpdate = addFieldsToUpdate;
// string array of additional fields with the same key when found
// in the jsonObject will be used to update the field with id
equal to
// key + 'Id'
// using the select jsonObject from the jsonResultSet which is a
jsonArray
this.warnIfNotFound = warnIfNotFound;
// boolean flag that is used to warn when fields to be updated are
not found
// or fieldsToBeDisplayed are not available as keys in the
jsonObject
},

getUpdatedChoices: function() {
this.startIndicator();

var entry = encodeURIComponent(this.options.paramName) + '=' +
encodeURIComponent(this.getToken());

this.options.parameters = this.options.callback ?
this.options.callback(this.element, entry) : entry;

if(this.options.defaultParams)
this.options.parameters += '&' + this.options.defaultParams;

new Ajax.Request(this.url, this.options);
},

// updates the div with the content you want to show and the user to
select from!
onComplete: function(request) {

// this method checks if the JSON response object has a property with
lookupFieldName
/*var jsonObject = request.responseText.evalJSON();
var lookupFieldName = 'value';
var updatedChoicesText = '<ul>';
jsonObject.each(function(jsonObj){
if(!(jsonObj[lookupFieldName] === undefined ))
updatedChoicesText = updatedChoicesText + '<li>' + jsonObj
[lookupFieldName] + '</li>';
});
updatedChoicesText = updatedChoicesText + '</ul>';
this.updateChoices(updatedChoicesText);*/

// this method looks up your JSON object for a property with the
same
// name as that of the element name of the field that is being
looked up!
// using the 'name' attribute and not the 'id' attribute!
var jsonObject = request.responseText.evalJSON();
var lookupFieldName = this.element.name; // element to be updated!

// display the other properties that were also requested in the
parameters
// var paramKeys = Object.keys(this.options.parameters.parseQuery());
// this.options.parameters.parseQuery() is an object with keys and
values

// collect all of the keys and remove the main key, the name of the
element
// the user needs an autocompletion on, as it HAS to be added in the
beginning
// as this is what the user is searching
// Object.keys(jsonObject[0]) will also give all of the fieldNames
// var jsonObjectKeys = Object.keys(jsonObject[0]);

// references to form fields that have to be displayedInDiv
var addFieldsToDisplayKeys = this.addFieldsToDisplay; //
addFieldsToUpdate

// remove the autocomplete field key which is the name equivalent and
not id!
addFieldsToDisplayKeys = addFieldsToDisplayKeys.reject(function(key)
{ return key == lookupFieldName;});
// you have to pass an iterator to the reject() function
// that returns those not matching according to your condition
// in order to remove an element that matches

var updatedChoicesText = "<ul id='divListId'>";

this.jsonResultSet = jsonObject;

// For each jsonObject parse each of the remaining keys and
// construct the string for display
var i = 0;
jsonObject.each(function(jsonObj) {
// this autocompletion field name HAS to exist, doesn't this make
sense?
if (!(jsonObj[lookupFieldName] === undefined))
{
updatedChoicesText = updatedChoicesText + '<li id=' + (i++) + '>'
+ jsonObj[lookupFieldName] + ' ';

// check if value exists for each of key before adding!
addFieldsToDisplayKeys.each(function(fieldKey){
if(!(jsonObj[fieldKey] === undefined))
{
updatedChoicesText = updatedChoicesText + fieldKey.capitalize()
+ ': ' +
jsonObj[fieldKey] + ' ';
}
else
{
if(this.warnIfNotFound)
alert('json object does not have a key for the field: ' +
fieldKey + ' that was requested to be displayed in the autocomplete');
}
});
updatedChoicesText = updatedChoicesText + '</li>';
}
else
{
if(this.warnIfNotFound)
alert('json object does not have a key same as the name property:
' + lookupFieldName + ' of the autocomplete field ');
}
});
updatedChoicesText = updatedChoicesText + '</ul>';
this.updateChoices(updatedChoicesText);
}
});

// The local array autocompleter. Used when you'd prefer to
// inject an array of autocompletion options into the page, rather
// than sending out Ajax queries, which can be quite slow sometimes.
//
// The constructor takes four parameters. The first two are, as usual,
// the id of the monitored textbox, and id of the autocompletion menu.
// The third is the array you want to autocomplete from, and the
fourth
// is the options block.
//
// Extra local autocompletion options:
// - choices - How many autocompletion choices to offer
//
// - partialSearch - If false, the autocompleter will match entered
// text only at the beginning of strings in the
// autocomplete array. Defaults to true, which will
// match text at the beginning of any *word* in the
// strings in the autocomplete array. If you want
to
// search anywhere in the string, additionally set
// the option fullSearch to true (default: off).
//
// - fullSsearch - Search anywhere in autocomplete array strings.
//
// - partialChars - How many characters to enter before triggering
// a partial match (unlike minChars, which defines
// how many characters are required to do any match
// at all). Defaults to 2.
//
// - ignoreCase - Whether to ignore case when autocompleting.
// Defaults to true.
//
// It's possible to pass in a custom function as the 'selector'
// option, if you prefer to write your own autocompletion logic.
// In that case, the other options above will not apply unless
// you support them.

Autocompleter.Local = Class.create(Autocompleter.Base, {
initialize: function(element, update, array, options) {
this.baseInitialize(element, update, options);
this.options.array = array;
},

getUpdatedChoices: function() {
this.updateChoices(this.options.selector(this));
},

setOptions: function(options) {
this.options = Object.extend({
choices: 10,
partialSearch: true,
partialChars: 2,
ignoreCase: true,
fullSearch: false,
selector: function(instance) {
var ret = []; // Beginning matches
var partial = []; // Inside matches
var entry = instance.getToken();
var count = 0;

for (var i = 0; i < instance.options.array.length &&
ret.length < instance.options.choices ; i++) {

var elem = instance.options.array[i];
var foundPos = instance.options.ignoreCase ?
elem.toLowerCase().indexOf(entry.toLowerCase()) :
elem.indexOf(entry);

while (foundPos != -1) {
if (foundPos == 0 && elem.length != entry.length) {
ret.push("<li><strong>" + elem.substr(0, entry.length) +
"</strong>" +
elem.substr(entry.length) + "</li>");
break;
} else if (entry.length >= instance.options.partialChars
&&
instance.options.partialSearch && foundPos != -1) {
if (instance.options.fullSearch || /\s/.test(elem.substr
(foundPos-1,1))) {
partial.push("<li>" + elem.substr(0, foundPos) +
"<strong>" +
elem.substr(foundPos, entry.length) + "</strong>" +
elem.substr(
foundPos + entry.length) + "</li>");
break;
}
}

foundPos = instance.options.ignoreCase ?
elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos
+ 1) :
elem.indexOf(entry, foundPos + 1);

}
}
if (partial.length)
ret = ret.concat(partial.slice(0, instance.options.choices -
ret.length))
return "<ul>" + ret.join('') + "</ul>";
}
}, options || { });
}
});

// AJAX in-place editor and collection editor
// Full rewrite by Christophe Porteneuve <t...@tddsworld.com> (April
2007).

// Use this if you notice weird scrolling problems on some browsers,
// the DOM might be a bit confused when this gets called so do this
// waits 1 ms (with setTimeout) until it does the activation
Field.scrollFreeActivate = function(field) {
setTimeout(function() {
Field.activate(field);
}, 1);
}

Ajax.InPlaceEditor = Class.create({
initialize: function(element, url, options) {
this.url = url;
this.element = element = $(element);
this.prepareOptions();
this._controls = { };
arguments.callee.dealWithDeprecatedOptions(options); //
DEPRECATION LAYER!!!
Object.extend(this.options, options || { });
if (!this.options.formId && this.element.id) {
this.options.formId = this.element.id + '-inplaceeditor';
if ($(this.options.formId))
this.options.formId = '';
}
if (this.options.externalControl)
this.options.externalControl = $(this.options.externalControl);
if (!this.options.externalControl)
this.options.externalControlOnly = false;
this._originalBackground = this.element.getStyle('background-
color') || 'transparent';
this.element.title = this.options.clickToEditText;
this._boundCancelHandler = this.handleFormCancellation.bind(this);
this._boundComplete = (this.options.onComplete ||
Prototype.emptyFunction).bind(this);
this._boundFailureHandler = this.handleAJAXFailure.bind(this);
this._boundSubmitHandler = this.handleFormSubmission.bind(this);
this._boundWrapperHandler = this.wrapUp.bind(this);
this.registerListeners();
},
checkForEscapeOrReturn: function(e) {
if (!this._editing || e.ctrlKey || e.altKey || e.shiftKey) return;
if (Event.KEY_ESC == e.keyCode)
this.handleFormCancellation(e);
else if (Event.KEY_RETURN == e.keyCode)
this.handleFormSubmission(e);
},
createControl: function(mode, handler, extraClasses) {
var control = this.options[mode + 'Control'];
var text = this.options[mode + 'Text'];
if ('button' == control) {
var btn = document.createElement('input');
btn.type = 'submit';
btn.value = text;
btn.className = 'editor_' + mode + '_button';
if ('cancel' == mode)
btn.onclick = this._boundCancelHandler;
this._form.appendChild(btn);
this._controls[mode] = btn;
} else if ('link' == control) {
var link = document.createElement('a');
link.href = '#';
link.appendChild(document.createTextNode(text));
link.onclick = 'cancel' == mode ? this._boundCancelHandler :
this._boundSubmitHandler;
link.className = 'editor_' + mode + '_link';
if (extraClasses)
link.className += ' ' + extraClasses;
this._form.appendChild(link);
this._controls[mode] = link;
}
},
createEditField: function() {
var text = (this.options.loadTextURL ? this.options.loadingText :
this.getText());
var fld;
if (1 >= this.options.rows && !/\r|\n/.test(this.getText())) {
fld = document.createElement('input');
fld.type = 'text';
var size = this.options.size || this.options.cols || 0;
if (0 < size) fld.size = size;
} else {
fld = document.createElement('textarea');
fld.rows = (1 >= this.options.rows ? this.options.autoRows :
this.options.rows);
fld.cols = this.options.cols || 40;
}
fld.name = this.options.paramName;
fld.value = text; // No HTML breaks conversion anymore
fld.className = 'editor_field';
if (this.options.submitOnBlur)
fld.onblur = this._boundSubmitHandler;
this._controls.editor = fld;
if (this.options.loadTextURL)
this.loadExternalText();
this._form.appendChild(this._controls.editor);
},
createForm: function() {
var ipe = this;
function addText(mode, condition) {
var text = ipe.options['text' + mode + 'Controls'];
if (!text || condition === false) return;
ipe._form.appendChild(document.createTextNode(text));
};
this._form = $(document.createElement('form'));
this._form.id = this.options.formId;
this._form.addClassName(this.options.formClassName);
this._form.onsubmit = this._boundSubmitHandler;
this.createEditField();
if ('textarea' == this._controls.editor.tagName.toLowerCase())
this._form.appendChild(document.createElement('br'));
if (this.options.onFormCustomization)
this.options.onFormCustomization(this, this._form);
addText('Before', this.options.okControl ||
this.options.cancelControl);
this.createControl('ok', this._boundSubmitHandler);
addText('Between', this.options.okControl &&
this.options.cancelControl);
this.createControl('cancel', this._boundCancelHandler,
'editor_cancel');
addText('After', this.options.okControl ||
this.options.cancelControl);
},
destroy: function() {
if (this._oldInnerHTML)
this.element.innerHTML = this._oldInnerHTML;
this.leaveEditMode();
this.unregisterListeners();
},
enterEditMode: function(e) {
if (this._saving || this._editing) return;
this._editing = true;
this.triggerCallback('onEnterEditMode');
if (this.options.externalControl)
this.options.externalControl.hide();
this.element.hide();
this.createForm();
this.element.parentNode.insertBefore(this._form, this.element);
if (!this.options.loadTextURL)
this.postProcessEditField();
if (e) Event.stop(e);
},
enterHover: function(e) {
if (this.options.hoverClassName)
this.element.addClassName(this.options.hoverClassName);
if (this._saving) return;
this.triggerCallback('onEnterHover');
},
getText: function() {
return this.element.innerHTML;
},
handleAJAXFailure: function(transport) {
this.triggerCallback('onFailure', transport);
if (this._oldInnerHTML) {
this.element.innerHTML = this._oldInnerHTML;
this._oldInnerHTML = null;
}
},
handleFormCancellation: function(e) {
this.wrapUp();
if (e) Event.stop(e);
},
handleFormSubmission: function(e) {
var form = this._form;
var value = $F(this._controls.editor);
this.prepareSubmission();
var params = this.options.callback(form, value);
params = (params ? params + '&' : '?') + 'editorId=' +
this.element.id;
if (this.options.htmlResponse) {
var options = Object.extend({ evalScripts: true },
this.options.ajaxOptions);
Object.extend(options, {
parameters: params,
onComplete: this._boundWrapperHandler,
onFailure: this._boundFailureHandler
});
new Ajax.Updater({ success: this.element }, this.url, options);
} else {
var options = Object.extend({ method: 'get' },
this.options.ajaxOptions);
Object.extend(options, {
parameters: params,
onComplete: this._boundWrapperHandler,
onFailure: this._boundFailureHandler
});
new Ajax.Request(this.url, options);
}
if (e) Event.stop(e);
},
leaveEditMode: function() {
this.element.removeClassName(this.options.savingClassName);
this.removeForm();
this.leaveHover();
this.element.style.backgroundColor = this._originalBackground;
this.element.show();
if (this.options.externalControl)
this.options.externalControl.show();
this._saving = false;
this._editing = false;
this._oldInnerHTML = null;
this.triggerCallback('onLeaveEditMode');
},
leaveHover: function(e) {
if (this.options.hoverClassName)
this.element.removeClassName(this.options.hoverClassName);
if (this._saving) return;
this.triggerCallback('onLeaveHover');
},
loadExternalText: function() {
this._form.addClassName(this.options.loadingClassName);
this._controls.editor.disabled = true;
var options = Object.extend({ method: 'get' },
this.options.ajaxOptions);
Object.extend(options, {
parameters: 'editorId=' + encodeURIComponent(this.element.id),
onComplete: Prototype.emptyFunction,
onSuccess: function(transport) {
this._form.removeClassName(this.options.loadingClassName);
var text = transport.responseText;
if (this.options.stripLoadedTextTags)
text = text.stripTags();
this._controls.editor.value = text;
this._controls.editor.disabled = false;
this.postProcessEditField();
}.bind(this),
onFailure: this._boundFailureHandler
});
new Ajax.Request(this.options.loadTextURL, options);
},
postProcessEditField: function() {
var fpc = this.options.fieldPostCreation;
if (fpc)
$(this._controls.editor)['focus' == fpc ? 'focus' : 'activate']
();
},
prepareOptions: function() {
this.options = Object.clone(Ajax.InPlaceEditor.DefaultOptions);
Object.extend(this.options, Ajax.InPlaceEditor.DefaultCallbacks);
[this._extraDefaultOptions].flatten().compact().each(function
(defs) {
Object.extend(this.options, defs);
}.bind(this));
},
prepareSubmission: function() {
this._saving = true;
this.removeForm();
this.leaveHover();
this.showSaving();
},
registerListeners: function() {
this._listeners = { };
var listener;
$H(Ajax.InPlaceEditor.Listeners).each(function(pair) {
listener = this[pair.value].bind(this);
this._listeners[pair.key] = listener;
if (!this.options.externalControlOnly)
this.element.observe(pair.key, listener);
if (this.options.externalControl)
this.options.externalControl.observe(pair.key, listener);
}.bind(this));
},
removeForm: function() {
if (!this._form) return;
this._form.remove();
this._form = null;
this._controls = { };
},
showSaving: function() {
this._oldInnerHTML = this.element.innerHTML;
this.element.innerHTML = this.options.savingText;
this.element.addClassName(this.options.savingClassName);
this.element.style.backgroundColor = this._originalBackground;
this.element.show();
},
triggerCallback: function(cbName, arg) {
if ('function' == typeof this.options[cbName]) {
this.options[cbName](this, arg);
}
},
unregisterListeners: function() {
$H(this._listeners).each(function(pair) {
if (!this.options.externalControlOnly)
this.element.stopObserving(pair.key, pair.value);
if (this.options.externalControl)
this.options.externalControl.stopObserving(pair.key,
pair.value);
}.bind(this));
},
wrapUp: function(transport) {
this.leaveEditMode();
// Can't use triggerCallback due to backward compatibility:
requires
// binding + direct element
this._boundComplete(transport, this.element);
}
});

Object.extend(Ajax.InPlaceEditor.prototype, {
dispose: Ajax.InPlaceEditor.prototype.destroy
});

Ajax.InPlaceCollectionEditor = Class.create(Ajax.InPlaceEditor, {
initialize: function($super, element, url, options) {
this._extraDefaultOptions =
Ajax.InPlaceCollectionEditor.DefaultOptions;
$super(element, url, options);
},

createEditField: function() {
var list = document.createElement('select');
list.name = this.options.paramName;
list.size = 1;
this._controls.editor = list;
this._collection = this.options.collection || [];
if (this.options.loadCollectionURL)
this.loadCollection();
else
this.checkForExternalText();
this._form.appendChild(this._controls.editor);
},

loadCollection: function() {
this._form.addClassName(this.options.loadingClassName);
this.showLoadingText(this.options.loadingCollectionText);
var options = Object.extend({ method: 'get' },
this.options.ajaxOptions);
Object.extend(options, {
parameters: 'editorId=' + encodeURIComponent(this.element.id),
onComplete: Prototype.emptyFunction,
onSuccess: function(transport) {
var js = transport.responseText.strip();
if (!/^\[.*\]$/.test(js)) // TODO: improve sanity check
throw 'Server returned an invalid collection
representation.';
this._collection = eval(js);
this.checkForExternalText();
}.bind(this),
onFailure: this.onFailure
});
new Ajax.Request(this.options.loadCollectionURL, options);
},

showLoadingText: function(text) {
this._controls.editor.disabled = true;
var tempOption = this._controls.editor.firstChild;
if (!tempOption) {
tempOption = document.createElement('option');
tempOption.value = '';
this._controls.editor.appendChild(tempOption);
tempOption.selected = true;
}
tempOption.update((text || '').stripScripts().stripTags());
},

checkForExternalText: function() {
this._text = this.getText();
if (this.options.loadTextURL)
this.loadExternalText();
else
this.buildOptionList();
},

loadExternalText: function() {
this.showLoadingText(this.options.loadingText);
var options = Object.extend({ method: 'get' },
this.options.ajaxOptions);
Object.extend(options, {
parameters: 'editorId=' + encodeURIComponent(this.element.id),
onComplete: Prototype.emptyFunction,
onSuccess: function(transport) {
this._text = transport.responseText.strip();
this.buildOptionList();
}.bind(this),
onFailure: this.onFailure
});
new Ajax.Request(this.options.loadTextURL, options);
},

buildOptionList: function() {
this._form.removeClassName(this.options.loadingClassName);
this._collection = this._collection.map(function(entry) {
return 2 === entry.length ? entry : [entry, entry].flatten();
});
var marker = ('value' in this.options) ? this.options.value :
this._text;
var textFound = this._collection.any(function(entry) {
return entry[0] == marker;
}.bind(this));
this._controls.editor.update('');
var option;
this._collection.each(function(entry, index) {
option = document.createElement('option');
option.value = entry[0];
option.selected = textFound ? entry[0] == marker : 0 == index;
option.appendChild(document.createTextNode(entry[1]));
this._controls.editor.appendChild(option);
}.bind(this));
this._controls.editor.disabled = false;
Field.scrollFreeActivate(this._controls.editor);
}
});

//**** DEPRECATION LAYER FOR InPlace[Collection]Editor! ****
//**** This only exists for a while, in order to let ****
//**** users adapt to the new API. Read up on the new ****
//**** API and convert your code to it ASAP! ****

Ajax.InPlaceEditor.prototype.initialize.dealWithDeprecatedOptions =
function(options) {
if (!options) return;
function fallback(name, expr) {
if (name in options || expr === undefined) return;
options[name] = expr;
};
fallback('cancelControl', (options.cancelLink ? 'link' :
(options.cancelButton ? 'button' :
options.cancelLink == options.cancelButton == false ? false :
undefined)));
fallback('okControl', (options.okLink ? 'link' : (options.okButton ?
'button' :
options.okLink == options.okButton == false ? false :
undefined)));
fallback('highlightColor', options.highlightcolor);
fallback('highlightEndColor', options.highlightendcolor);
};

Object.extend(Ajax.InPlaceEditor, {
DefaultOptions: {
ajaxOptions: { },
autoRows: 3, // Use when multi-line
w/ rows == 1
cancelControl: 'link', // 'link'|'button'|
false
cancelText: 'cancel',
clickToEditText: 'Click to edit',
externalControl: null, // id|elt
externalControlOnly: false,
fieldPostCreation: 'activate', // 'activate'|'focus'|
false
formClassName: 'inplaceeditor-form',
formId: null, // id|elt
highlightColor: '#ffff99',
highlightEndColor: '#ffffff',
hoverClassName: '',
htmlResponse: true,
loadingClassName: 'inplaceeditor-loading',
loadingText: 'Loading...',
okControl: 'button', // 'link'|'button'|
false
okText: 'ok',
paramName: 'value',
rows: 1, // If 1 and multi-
line, uses autoRows
savingClassName: 'inplaceeditor-saving',
savingText: 'Saving...',
size: 0,
stripLoadedTextTags: false,
submitOnBlur: false,
textAfterControls: '',
textBeforeControls: '',
textBetweenControls: ''
},
DefaultCallbacks: {
callback: function(form) {
return Form.serialize(form);
},
onComplete: function(transport, element) {
// For backward compatibility, this one is bound to the IPE, and
passes
// the element directly. It was too often customized, so we
don't break it.
new Effect.Highlight(element, {
startcolor: this.options.highlightColor, keepBackgroundImage:
true });
},
onEnterEditMode: null,
onEnterHover: function(ipe) {
ipe.element.style.backgroundColor = ipe.options.highlightColor;
if (ipe._effect)
ipe._effect.cancel();
},
onFailure: function(transport, ipe) {
alert('Error communication with the server: ' +
transport.responseText.stripTags());
},
onFormCustomization: null, // Takes the IPE and its generated
form, after editor, before controls.
onLeaveEditMode: null,
onLeaveHover: function(ipe) {
ipe._effect = new Effect.Highlight(ipe.element, {
startcolor: ipe.options.highlightColor, endcolor:
ipe.options.highlightEndColor,
restorecolor: ipe._originalBackground, keepBackgroundImage:
true
});
}
},
Listeners: {
click: 'enterEditMode',
keydown: 'checkForEscapeOrReturn',
mouseover: 'enterHover',
mouseout: 'leaveHover'
}
});

Ajax.InPlaceCollectionEditor.DefaultOptions = {
loadingCollectionText: 'Loading options...'
};

// Delayed observer, like Form.Element.Observer,
// but waits for delay after last key input
// Ideal for live-search fields

Form.Element.DelayedObserver = Class.create({
initialize: function(element, delay, callback) {
this.delay = delay || 0.5;
this.element = $(element);
this.callback = callback;
this.timer = null;
this.lastValue = $F(this.element);
Event.observe
(this.element,'keyup',this.delayedListener.bindAsEventListener(this));
},
delayedListener: function(event) {
if(this.lastValue == $F(this.element)) return;
if(this.timer) clearTimeout(this.timer);
this.timer = setTimeout(this.onTimerEvent.bind(this), this.delay *
1000);
this.lastValue = $F(this.element);
},
onTimerEvent: function() {
this.timer = null;
this.callback(this.element, $F(this.element));
}
});

Thanks
Krishna
Message has been deleted

krishna

unread,
Mar 11, 2009, 11:44:09 AM3/11/09
to Prototype & script.aculo.us
David, I sent you a link using "Reply to author" as per your request
and will now download the
latest scriptaculous and test it!

Also, I see that there are other CSS issues which I will discuss once
I finish this!

krishna

unread,
Mar 11, 2009, 12:18:28 PM3/11/09
to Prototype & script.aculo.us
Ran the autoupdater functional test and autoupdater unit tests in
FF3.0.7 and IE7.0 and saw the unit tests failing in both IE and FF :(

scriptaculous-js-1.8.2\test\run_functional_tests.html
scriptaculous-js-1.8.2\test\run_unit_tests.html

and found that functional test passed in FF only, every thing else,
unit test in IE and FF and functional test in IE failed!

I did get the security warning in IE and I clicked the alert and allow
the activex content for these pages!

Help the newbie!
Krishna

krishna

unread,
Mar 11, 2009, 12:38:21 PM3/11/09
to Prototype & script.aculo.us
David,

It is the newbie again, I have updated all of my javascript files and
found that nothing changed, I still see the issue:
Ajax.Autocompleter blanks out the page (frame only) when used in an
Internet Explorer IE 7.0.5730.11 framed jsp!

I created a dummy web application and sent you the link just for you
to test, let me know if you want me to post the link here in the forum
for others to look at again?

SOS
Krishna

krishna

unread,
Mar 12, 2009, 12:17:39 AM3/12/09
to Prototype & script.aculo.us
After two full days of debugging using alerts and console prints in
IE7.0 and not giving up, I found that there is some piece of code
which when removed, worked for me in both IE and FF even when used
inside one of the frames! I wish someone could explain me the IE
thingy here!

search for CHANGES IN CODE where I block commented the code, wish if
someone could explain why they were there in the first place:

I hope this is the tradeoff for using open source code as they are not
tested completely :(

// script.aculo.us controls.js v1.8.2, Tue Nov 18 18:30:58 +0100 2008

// Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us,
http://mir.aculo.us)
// (c) 2005-2008 Ivan Krstic (http://blogs.law.harvard.edu/
ivan)
// (c) 2005-2008 Jon Tirsen (http://www.tirsen.com)
// setTimeout("console.log('is IE:' + Prototype.Browser.IE);",
5000);
// setTimeout("console.log('in function(element,update)
method: ' + update);",5000);

update.style.position = 'absolute';

// CHANGES IN CODE
/*Position.clone(element, update, {
setHeight: false,
offsetTop: element.offsetHeight
});*/
}

Effect.Appear(update,{duration:0.15});

// setTimeout("console.log('out of function(element,update)
method: after running update');",5000);

};
this.options.onHide = this.options.onHide ||
function(element, update){ new Effect.Fade(update,{duration:
0.15}) };

if(typeof(this.options.tokens) == 'string')
this.options.tokens = new Array(this.options.tokens);
// Force carriage returns as token delimiters anyway
if (!this.options.tokens.include('\n'))
this.options.tokens.push('\n');

this.observer = null;

this.element.setAttribute('autocomplete','off');

Element.hide(this.update);

Event.observe(this.element, 'blur', this.onBlur.bindAsEventListener
(this));
Event.observe(this.element, 'keydown',
this.onKeyPress.bindAsEventListener(this));
},

show: function() {
if(Element.getStyle(this.update, 'display')=='none')
this.options.onShow(this.element, this.update);

// setTimeout("console.log('The ID of the iframe in IE only -
this.iefix: ' + this.iefix);",5000);

if(!this.iefix &&
(Prototype.Browser.IE) &&
(Element.getStyle(this.update, 'position')=='absolute')) {
new Insertion.After(this.update,
'<iframe id="' + this.update.id + '_iefix" '+

'style="display:none;position:absolute;filter:progid:DXImageTransform.Microsoft.Alpha
(opacity=0);" ' +
'src="javascript:false;" frameborder="0" scrolling="no"></
iframe>');

this.iefix = $(this.update.id+'_iefix');

// setTimeout("console.log('out of show()');",5000);

}
// changed time: CHANGES IN CODE
// if(this.iefix) setTimeout(this.fixIEOverlapping.bind(this),
1000);
},

fixIEOverlapping: function() {

// setTimeout("console.log('in fixIEOverlapping');",5000);

console.dir('printing the divs style: update.style: ' +
this.update.style);
console.dir('printing the iefix style: iefix.style: ' +
this.iefix.style);

// causes the IE7.0 to freeze frame!
// CHANGES IN CODE
/*Position.clone(this.update, this.iefix, {setTop:(!
this.update.style.height)});
this.iefix.style.zIndex = 1;
this.update.style.zIndex = 2;
Element.show(this.iefix);
*/

// setTimeout("console.log('out of fixIEOverlapping()');",5000);

},

hide: function() {
// setTimeout("console.log('in hide()');",5000);
this.stopIndicator();
if(Element.getStyle(this.update, 'display')!='none')
this.options.onHide(this.element, this.update);
if(this.iefix) Element.hide(this.iefix);
// setTimeout("console.log('out of hide()');",5000);
Event.stop(event);
return;
case Event.KEY_DOWN:
this.markNext();
this.render();
// setTimeout("console.log('out of onBlur')",5000);
},

render: function() {

// setTimeout("console.log('in render()');",5000);

if(this.entryCount > 0) {
for (var i = 0; i < this.entryCount; i++)
this.index==i ?
Element.addClassName(this.getEntry(i),"selected") :
Element.removeClassName(this.getEntry(i),"selected");
if(this.hasFocus) {
this.show();
this.active = true;
}
} else {
this.active = false;
this.hide();
}

// setTimeout("console.log('out of render()');",5000);

},

markPrevious: function() {
if(this.index > 0) this.index--;
else this.index = this.entryCount-1;
this.getEntry(this.index).scrollIntoView(true);
},

markNext: function() {
if(this.index < this.entryCount-1) this.index++;
else this.index = 0;
this.getEntry(this.index).scrollIntoView(false);
},

getEntry: function(index) {
return this.update.firstChild.childNodes[index];
},

getCurrentEntry: function() {
return this.getEntry(this.index);
},

selectEntry: function() {
this.active = false;
this.updateElement(this.getCurrentEntry());
},

updateElement: function(selectedElement) {

// setTimeout("console.log('entered updateElement()');",5000);
// this.element.value in appearing next two times was commented
to update
// directly based on key passed and whose id = key + 'Id'
// this.element.value = newValue + value +
this.element.value.substr(bounds[1]);
} else {
// this.element.value = value;
}
this.oldElementValue = this.element.value;
this.element.focus();

if (this.options.afterUpdateElement)
this.options.afterUpdateElement(this.element, selectedElement);

// setTimeout("console.log('out of updateElement()');",5000);
// setTimeout("console.log('in getUpdatedChoices()');",5000);

var entry = encodeURIComponent(this.options.paramName) + '=' +
encodeURIComponent(this.getToken());

this.options.parameters = this.options.callback ?
this.options.callback(this.element, entry) : entry;

if(this.options.defaultParams)
this.options.parameters += '&' + this.options.defaultParams;

new Ajax.Request(this.url, this.options);

// setTimeout("console.log('out of getUpdatedChoices()');",5000);
},

// updates the div with the content you want to show and the user to
select from!
onComplete: function(request) {

// setTimeout("console.log('inside onComplete()');",5000);
// setTimeout("console.log('out of onComplete()');",5000);
return this.element.innerHTML.unescapeHTML();
},
handleAJAXFailure: function(transport) {
this.triggerCallback('onFailure', transport);
if (this._oldInnerHTML) {
this.element.innerHTML = this._oldInnerHTML;
this._oldInnerHTML = null;
}
},
handleFormCancellation: function(e) {
this.wrapUp();
if (e) Event.stop(e);
},
handleFormSubmission: function(e) {
var form = this._form;
var value = $F(this._controls.editor);
this.prepareSubmission();
var params = this.options.callback(form, value) || '';
if (Object.isString(params))
params = params.toQueryParams();
params.editorId = this.element.id;
throw('Server returned an invalid collection
representation.');

david

unread,
Mar 12, 2009, 7:42:24 AM3/12/09
to Prototype & script.aculo.us
Hi krishna,

it seems that I did not do much for you, you help yourself :))
The major problem in this kind of library is that it try to handle all
possibilities, and with browser that do not handle things the same
way, it's very difficult to create something that couldn't fail in
little case, like yours.

The code you commented out is generally the Position.Clone method with
as it is said clone the position of one element to another element
with some interresting options.
The iefix element is as explain a special element to try to fix IE
BUGGGS.

btw, If you have some times, just open a ticket in
http://prototype.lighthouseapp.com/projects/8887-script-aculo-us with
the problem you had, and the resolution code. It probably could help
someone else.

--
david

On 12 mar, 05:17, krishna <chikkub...@gmail.com> wrote:
> After two full days of debugging using alerts and console prints in
> IE7.0 and not giving up, I found that there is some piece of code
> which when removed, worked for me in both IE and FF even when used
> inside one of the frames! I wish someone could explain me the IE
> thingy here!
>
> search for CHANGES IN CODE where I block commented the code, wish if
> someone could explain why they were there in the first place:
>
> I hope this is the tradeoff for using open source code as they are not
> tested completely :(
>
> // script.aculo.us controls.js v1.8.2, Tue Nov 18 18:30:58 +0100 2008
>
> // Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us,http://mir.aculo.us)
> ...
>
> plus de détails »

krishna

unread,
Mar 18, 2009, 12:19:01 PM3/18/09
to Prototype & script.aculo.us
Hi David,

I have raised a ticket as per your suggestion:

http://prototype.lighthouseapp.com/projects/8887-script-aculo-us/tickets/183

Regards
Krishna
Reply all
Reply to author
Forward
0 new messages